﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using QuickGraph;
using QuickGraph.Graphviz;
using System.Xml;

namespace DTO
{
    public class Relationship
    {
        #region Attributes
        int concept1ID;
        int concept2ID;
        int score;
        List<Link> linkList;
        #endregion

        #region Properties
        /// <summary>
        /// The list of all links in this relationship between instances of 2 concepts.
        /// </summary>
        public List<Link> LinkList
        {
            get { return linkList; }
            set { linkList = value; }
        }

        /// <summary>
        /// The ID of the source concept
        /// </summary>
        public int Concept1ID
        {
            get
            {
                return concept1ID;
            }
            set
            {
                concept1ID = value;
            }
        }

        /// <summary>
        /// The ID of the destination concept
        /// </summary>
        public int Concept2ID
        {
            get
            {
                return concept2ID;
            }
            set
            {
                concept2ID = value;
            }
        }

        /// <summary>
        /// The score of this relationship based on the number of hyperlinks between instances of 2 concepts
        /// </summary>
        public int Score
        {
            get
            {
                return score;
            }
            set
            {
                score = value;
            }
        }
        #endregion

        #region Constructors
        public Relationship()
        {
            this.linkList = new List<Link>();
        } 
        #endregion

        #region Methods
        /// <summary>
        /// This method iterates through the list of relationships to find the index of the relationship between concept 1 and concept 2
        /// </summary>
        /// <param name="relationshipList">List of relationships between concepts</param>
        /// <param name="concept1ID">ID of concept 1</param>
        /// <param name="concept2ID">ID of concept 2</param>
        /// <returns>Index of the found relationship, -1 if can not found</returns>
        public static int FindRelationship(List<Relationship> relationshipList, int concept1ID, int concept2ID)
        {
            for (int i = 0; i < relationshipList.Count; i++)
            {
                if (relationshipList[i].Concept1ID == concept1ID && relationshipList[i].Concept2ID == concept2ID)
                {
                    return i;
                }
            }
            return -1;
        }

        public static bool IsLinkExisting(List<Link> linkList, int sourceID, int destID)
        {
            for (int i = 0; i < linkList.Count; i++)
            {
                if (linkList[i].SourceWebpageID == sourceID && linkList[i].DestWebpageID == destID)
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// Export the list of relationships to xml file
        /// </summary>
        /// <param name="relationshipList">List of relationships</param>
        /// <param name="filePath">The path (with name) of the exported file</param>
        public static void ToRelationshipFile(List<Relationship> relationshipList, string filePath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            XmlElement xmlElementRoot = xmlDoc.CreateElement("relationship_discovery");
            xmlDoc.AppendChild(xmlElementRoot);

            foreach (Relationship curRelationship in relationshipList)
            {
                XmlElement xmlElementRelationship = xmlDoc.CreateElement("relationship");
                XmlAttribute xmlRelationshipAttribute = xmlDoc.CreateAttribute("sourceConcept");
                xmlRelationshipAttribute.Value = curRelationship.Concept1ID.ToString() ;
                xmlElementRelationship.Attributes.Append(xmlRelationshipAttribute);

                xmlRelationshipAttribute = xmlDoc.CreateAttribute("destConcept");
                xmlRelationshipAttribute.Value = curRelationship.Concept2ID.ToString();
                xmlElementRelationship.Attributes.Append(xmlRelationshipAttribute);

                xmlRelationshipAttribute = xmlDoc.CreateAttribute("score");
                xmlRelationshipAttribute.Value = curRelationship.Score.ToString();
                xmlElementRelationship.Attributes.Append(xmlRelationshipAttribute);

                XmlElement xmlLinks = xmlDoc.CreateElement("links");

                foreach (Link curLink in curRelationship.LinkList)
                {
                    XmlElement xmlLink = xmlDoc.CreateElement("link");
                    XmlAttribute xmlLinkAttribute = xmlDoc.CreateAttribute("sourceWebpage");
                    xmlLinkAttribute.Value = curLink.SourceWebpageID.ToString();
                    xmlLink.Attributes.Append(xmlLinkAttribute);

                    xmlLinkAttribute = xmlDoc.CreateAttribute("destWebpage");
                    xmlLinkAttribute.Value = curLink.DestWebpageID.ToString();
                    xmlLink.Attributes.Append(xmlLinkAttribute);

                    xmlLinks.AppendChild(xmlLink);
                }
                xmlElementRelationship.AppendChild(xmlLinks);

                xmlElementRoot.AppendChild(xmlElementRelationship);            
            }

            try
            {
                xmlDoc.Save(filePath);
            }
            catch
            {

            }
        }
        
        /// <summary>
        /// Import the list of relationships from xml file
        /// </summary>
        /// <param name="filePath">The path (with name) of the exported file</param>
        /// <returns>The list of relationship imported from file</returns>
        public static List<Relationship> FromRelationshipFile(string filePath)
        {
            List<Relationship> relationshipList = new List<Relationship>();

            XmlDocument xmlDoc = new XmlDocument();
            try
            {
                xmlDoc.Load(filePath);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            XmlNodeList xmlRelationshipList = xmlDoc.GetElementsByTagName("relationship");
            foreach (XmlNode curRelationshipNode in xmlRelationshipList)
            {
                Relationship curRelationship = new Relationship();
                curRelationship.Concept1ID = Int32.Parse(curRelationshipNode.Attributes.GetNamedItem("sourceConcept").Value);
                curRelationship.Concept2ID = Int32.Parse(curRelationshipNode.Attributes.GetNamedItem("destConcept").Value);
                curRelationship.Score = Int32.Parse(curRelationshipNode.Attributes.GetNamedItem("score").Value);

                Link tempLink = new Link();
                curRelationship.LinkList = new List<Link>();
                foreach (XmlNode curLinkNode in curRelationshipNode.FirstChild.ChildNodes)
                {
                    tempLink = new Link();
                    tempLink.SourceWebpageID = Int32.Parse(curLinkNode.Attributes.GetNamedItem("sourceWebpage").Value);
                    tempLink.DestWebpageID = Int32.Parse(curLinkNode.Attributes.GetNamedItem("destWebpage").Value);
                    curRelationship.LinkList.Add(tempLink);
                }
                relationshipList.Add(curRelationship);
            }
            return relationshipList;
        }

        public static string RelationshipToGraphInDotFormat(List<Relationship> relationshipList, string filePath)
        {
            string dotStr = string.Empty;
            dotStr += "digraph G {\n";
            dotStr += "node [shape=circle];\n";

            HashSet<int> conceptHS = new HashSet<int>();
            foreach (Relationship curRelationship in relationshipList)
            {
                conceptHS.Add(curRelationship.Concept1ID);
                conceptHS.Add(curRelationship.Concept2ID);
            }

            // add vertices
            foreach (int curConceptID in conceptHS)
            {
                dotStr += curConceptID + " ;\n";
            }

            // add edges
            foreach (Relationship curRelationship in relationshipList)
            {
                dotStr += curRelationship.Concept1ID + " -> " + curRelationship.Concept2ID + " [label=\"" + curRelationship.Score + "\" weight=\"" + curRelationship.Score + "\"];\n"; 
            }
            dotStr += ";";
            return dotStr;
        }
        #endregion
    }
}
